package com.bootdo.wx.api;

import com.bootdo.common.utils.*;
import com.bootdo.wx.domain.MemberPriceDO;
import com.bootdo.wx.domain.MemberUserDO;
import com.bootdo.wx.domain.OrderOrderDO;
import com.bootdo.wx.domain.SetWechatDO;
import com.bootdo.wx.service.*;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.apache.velocity.texen.util.PropertiesUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.security.KeyStore;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by HP on 2019/7/13.
 */
@Controller
@RequestMapping("/api/wxPay")
public class ApiWeChatPayController {

    @Autowired
    private SetWechatService setWechatService;
    @Autowired
    private OrderOrderService orderOrderService;
    @Autowired
    private MemberUserService memberUserService;
    @Autowired
    private OrderComService orderComService;
    @Autowired
    private MemberPriceService memberPriceService;
    @Autowired
    private WeChatPayService weChatPayService;


    private final Logger log = LoggerFactory.getLogger(this.getClass());



    /**
     * 微信下单支付接口
     *
     * @param params
     * @param req
     * @return
     */
    @RequestMapping("/pay")
    @ResponseBody
    public R pay(@RequestBody Map<String, Object> params, HttpServletRequest req) {
        try {
//            log.debug("map::" + Json.toJson(map));
            if (!params.containsKey("orderId") || params.get("orderId").toString().isEmpty()
                    ||!params.containsKey("userId") || params.get("userId").toString().isEmpty()
                    ) {
                return R.error(100, "参数错误");
            }
            String orderId = params.get("orderId").toString();
            String userId = params.get("userId").toString();
            OrderOrderDO order = orderOrderService.get(orderId);
            if (order == null) {
                return R.error(101, "订单异常");
            }
            MemberUserDO userDO = memberUserService.get(userId);
            if (userDO == null) {
                return R.error(103, "用户异常");
            }
            SetWechatDO setWechatDO = setWechatService.list(new HashMap<String, Object>()).get(0);
            SortedMap<String, String> signMap = new TreeMap<>();


            signMap.put("body", "商品"); //商品描述  必

            //signMap.put("appId", goods.getIntro()); //应用ID  必
            //signMap.put("mch_id", goods.getGoodsName()); //商户号  必
            //signMap.put("sign_type", "MD5"); //签名类型默认MD5
            //signMap.put("notify_url", order.getTotalAmount()); //通知地址 回调url  必
            //signMap.put("trade_type", "APP"); //交易类型  APP 必
            //signMap.put("time_start", order.getTotalAmount()); //交易开始时间  必
            //signMap.put("time_expire", order.getTotalAmount()); //交易结束时间    大于5分钟
            //signMap.put("nonce_str", order.getOrderSn()); //随机字符串  必

//            signMap.put("body", goods.getGoodsName()); //商品描述  必
            signMap.put("attach", "商品"); //商品详情  非
            signMap.put("openid", userDO.getWechatOpenId()); //小程序支付必填，其他非填
            signMap.put("out_trade_no", order.getOrderSn()); //商户订单号  必
            /*float sessionmoney = Float.parseFloat(order.getPayment().toString());
            String finalmoney = String.format("%.2f", sessionmoney);
            finalmoney = finalmoney.replace(".", "");
            String newStr = finalmoney.replaceFirst("^0*", "");*/
            int total_fee  = Math.round(Float.valueOf(order.getPayment().multiply(new BigDecimal(100)).toString()));
            signMap.put("total_fee", String.valueOf(total_fee)); //总金额  必    /分
            /*signMap.put("total_fee", "1");    //先支付1分*/
            signMap.put("spbill_create_ip", StringUtils.getRemoteAddr(req)); //终端ip  用户端ip  必
            signMap.put("notify_url",setWechatDO.getUrl() + "/api/wxPay/weixinpayNotify");
            Map<String,Object> map = WeChatPayUtils.getOrderSignature(signMap,setWechatDO);

//            log.debug("weixin sign=="+wxorder);

//            logService.async(Mp_log.c(map.getString("appId"), map.getString("appSecret"), "", "user.weixinPay", "微信支付", "微信支付"));
            return R.ok().put("data", map);
        } catch (Exception e) {
            return R.error("微信支付失败!");
        }
    }

    /**
     * 余额支付
     */
    @PostMapping("/pricePay")
    @ResponseBody
    public R pricePay(@RequestBody Map<String, Object> params){
        if (!params.containsKey("userId") || !params.containsKey("userId")
                || !params.containsKey("orderId") || !params.containsKey("orderId")
                ){
            return R.error("参数异常");
        }
        try{
            String orderId = params.get("orderId").toString();
            String userId = params.get("userId").toString();
            OrderOrderDO order = orderOrderService.get(orderId);
            if (order == null) {
                return R.error(101, "订单异常");
            }
            MemberUserDO userDO = memberUserService.get(userId);
            if (userDO == null) {
                return R.error(103, "用户异常");
            }
            Map<String,Object> moneyMap = orderComService.getMemberCom(params);
            BigDecimal allPrice = new BigDecimal(moneyMap.get("allPrice").toString());   //余额
            BigDecimal payment = order.getPayment();
            if (allPrice.compareTo(payment) == -1) {
                return R.error("余额不足，请充值");
            }
            params.put("payType", "2");
            return orderOrderService.pricePay(params);
        }catch (Exception e){
            return R.error("服务器网络异常");
        }
    }


    /*微信下单支付回调*/
    @ResponseBody
    @RequestMapping("/weixinpayNotify")
    public Object weixinpayNotify(HttpServletRequest req, HttpServletResponse res) {
        try {
            InputStream inStream = req.getInputStream();
            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            System.out.println("~~~~~~~~~~~~~~~~付款成功~~~~~~~~~");
            outSteam.close();
            inStream.close();
            String result = new String(outSteam.toByteArray(), "utf-8");// 获取微信调用我们notify_url的返回信息
            Map<Object, Object> mapFromXml = PayCommonUtil.doXMLParse(result);
            log.error("mapFromXml::" + mapFromXml.toString());
            SortedMap<String ,String > sortedMap = new TreeMap();
            log.error("map001::");
            if (mapFromXml.get("result_code").toString().equalsIgnoreCase("SUCCESS")) {
                log.error("map002::");
                OrderOrderDO order = orderOrderService.getByOrder(mapFromXml.get("out_trade_no").toString());
                if (order.getStatus() == 1) {
                    log.error("map003::" + order.toString());
                    if (verifyWeixinNotify(mapFromXml)) {
                        log.error("map004::开始订单处理");
                        //订单处理
                        Map<String,Object> priceMap = new HashMap<String,Object>();
                        priceMap.put("userId",order.getUserId());
                        priceMap.put("orderId",order.getId());
                        priceMap.put("payType", "0");
                        R r = orderOrderService.pricePay(priceMap);

                       /* int post_type = order.getPostType();
                        if (post_type == 0) {  //自提
                            order.setStatus(11);
                        } else if (post_type == 1) {  //快递
                            order.setStatus(3);
                        }
                        order.setPaytype(0);
                        order.setPayAt(new Date());*/
                        log.error("map005::");
                        if (r.get("msg").toString().equals("0")) {
                            log.error("微信支付成功::");
                            // 告诉微信服务器，我收到信息了，不要在调用回调action了
                            sortedMap.put("return_code","SUCCESS");
                            sortedMap.put("return_msg","OK");
                            res.getWriter().write(parseXML(sortedMap));

                        } else {
                            log.error("微信支付失败，数据更新失败");
                        }

                    }else{
                        log.error("map011::");
                        sortedMap.put("return_code","FAIL");
                        sortedMap.put("return_msg","签名失败");
                        res.getWriter().write(parseXML(sortedMap));
                    }
                    log.error("map012::");
                } else {
                    log.error("map013::订单已经修改过了");
                }
            }
            log.error("map012::");
            return "success";
        } catch (Exception e) {
            return "failure";
        }
    }

    /**
     * 微信充值接口
     *
     * @param params
     * @param req
     * @return
     */
    @RequestMapping("/payTwo")
    @ResponseBody
    public R payTwo(@RequestBody Map<String, Object> params, HttpServletRequest req) {
        try {
//            log.debug("map::" + Json.toJson(map));
            if (!params.containsKey("money") || params.get("money").toString().isEmpty()
                    ||!params.containsKey("userId") || params.get("userId").toString().isEmpty()
                    ) {
                return R.error(100, "参数错误");
            }
            BigDecimal money = new BigDecimal(params.get("money").toString());
            String userId = params.get("userId").toString();
            MemberUserDO userDO = memberUserService.get(userId);
            if (userDO == null) {
                return R.error(103, "用户异常");
            }
            SetWechatDO setWechatDO = setWechatService.list(new HashMap<String, Object>()).get(0);
            SortedMap<String, String> signMap = new TreeMap<>();
            //插入充值记录
            MemberPriceDO priceDO = new MemberPriceDO();
            priceDO.setId(UuidUtil.get32UUID());
            priceDO.setType(2);
            priceDO.setUserId(userId);
            priceDO.setPrice(money);
            priceDO.setDelFlag(1);
            priceDO.setCreateAt(new Date());
            priceDO.setUpdateAt(new Date());
            memberPriceService.save(priceDO);

            signMap.put("body", "商品"); //商品描述  必

            //signMap.put("appId", goods.getIntro()); //应用ID  必
            //signMap.put("mch_id", goods.getGoodsName()); //商户号  必
            //signMap.put("sign_type", "MD5"); //签名类型默认MD5
            //signMap.put("notify_url", order.getTotalAmount()); //通知地址 回调url  必
            //signMap.put("trade_type", "APP"); //交易类型  APP 必
            //signMap.put("time_start", order.getTotalAmount()); //交易开始时间  必
            //signMap.put("time_expire", order.getTotalAmount()); //交易结束时间    大于5分钟
            //signMap.put("nonce_str", order.getOrderSn()); //随机字符串  必

//            signMap.put("body", goods.getGoodsName()); //商品描述  必
            signMap.put("attach", "充值"); //商品详情  非
            signMap.put("openid", userDO.getWechatOpenId()); //小程序支付必填，其他非填
            signMap.put("out_trade_no", priceDO.getId()); //商户订单号  必
            /*float sessionmoney = Float.parseFloat(order.getPayment().toString());
            String finalmoney = String.format("%.2f", sessionmoney);
            finalmoney = finalmoney.replace(".", "");
            String newStr = finalmoney.replaceFirst("^0*", "");*/
            int total_fee  = Math.round(Float.valueOf(money.multiply(new BigDecimal(100)).toString()));
            signMap.put("total_fee", String.valueOf(total_fee)); //总金额  必    /分
            /*signMap.put("total_fee", "1");  //先支付1分*/
            signMap.put("spbill_create_ip", StringUtils.getRemoteAddr(req)); //终端ip  用户端ip  必
            signMap.put("notify_url",setWechatDO.getUrl() + "/api/wxPay/weixinpayTwoNotify");
            Map<String,Object> map = WeChatPayUtils.getOrderSignature(signMap,setWechatDO);

//            log.debug("weixin sign=="+wxorder);

//            logService.async(Mp_log.c(map.getString("appId"), map.getString("appSecret"), "", "user.weixinPay", "微信支付", "微信支付"));
            return R.ok().put("data", map);
        } catch (Exception e) {
            return R.error("微信支付失败!");
        }
    }

    /*微信充值回调*/
    @ResponseBody
    @RequestMapping("/weixinpayTwoNotify")
    public Object weixinpayTwoNotify(HttpServletRequest req, HttpServletResponse res) {
        try {
            InputStream inStream = req.getInputStream();
            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            System.out.println("~~~~~~~~~~~~~~~~充值成功~~~~~~~~~");
            outSteam.close();
            inStream.close();
            String result = new String(outSteam.toByteArray(), "utf-8");// 获取微信调用我们notify_url的返回信息
            Map<Object, Object> mapFromXml = PayCommonUtil.doXMLParse(result);
            log.error("chongzhiFromXml::" + mapFromXml.toString());
            SortedMap<String ,String > sortedMap = new TreeMap();
            log.error("chongzhi001::");
            if (mapFromXml.get("result_code").toString().equalsIgnoreCase("SUCCESS")) {
                log.error("chongzhi002::");
                String priceId = mapFromXml.get("out_trade_no").toString();
                MemberPriceDO priceDO = memberPriceService.get(priceId);
                if (priceDO.getDelFlag() == 1) {
                    log.error("chongzhi003::priceId:" + priceId);
                    if (verifyWeixinNotify(mapFromXml)) {
                        log.error("chongzhi004::开始充值处理");
                        //订单处理
                        int o = memberPriceService.czSuccse(priceId);
                        log.error("chongzhi005::" + o);
                        if (o == 0) {
                            log.error("微信充值成功::");
                            // 告诉微信服务器，我收到信息了，不要在调用回调action了
                            sortedMap.put("return_code","SUCCESS");
                            sortedMap.put("return_msg","OK");
                            res.getWriter().write(parseXML(sortedMap));

                        }
                        log.error("微信充值失败，数据更新失败");
                    }else{
                        log.error("chongzhi011::");
                        sortedMap.put("return_code","FAIL");
                        sortedMap.put("return_msg","签名失败");
                        res.getWriter().write(parseXML(sortedMap));
                    }
                    log.error("map012::");
                } else {
                    log.error("map013::这笔充值已经处理过了");
                }

            }
            log.error("map012::");
            return "success";
        } catch (Exception e) {
            return "failure";
        }
    }


    public boolean verifyWeixinNotify(Map<Object, Object> map) {
        SetWechatDO setWechatDO = setWechatService.list(new HashMap<String, Object>()).get(0);
        SortedMap<String, Object> parameterMap = new TreeMap<String, Object>();
        String sign = (String) map.get("sign");
        for (Object keyValue : map.keySet()) {
            if(!keyValue.toString().equals("sign")){
                parameterMap.put(keyValue.toString(), map.get(keyValue));
            }
        }
        String createSign = PayCommonUtil.createSign("UTF-8", parameterMap,setWechatDO.getKey());
        if(createSign.equals(sign)){
            return true;
        }else{
            return false;
        }

    }

    //输出XML
    public String parseXML(Map map) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>\n");
        Set es = map.entrySet();
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            String v = (String)entry.getValue();
            if(null != v && !"".equals(v) && !"appkey".equals(k)) {

                sb.append("<" + k +">" + v + "</" + k + ">\n");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }

    //具体的调用微信的退款接口
    @ResponseBody
    @RequestMapping("/refund")
    public R refund(Map<String,Object> params) throws Exception{
        if (!params.containsKey("orderId") || params.get("orderId").toString().isEmpty()
                ) {
            return R.error(100, "参数错误");
        }
        return weChatPayService.refund(params);
    }



}
